#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <random>
#include <sstream>
#include <iomanip>
#include <atomic>
#include <fstream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cerrno>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <sqlite3.h>
#include "mq_logger.hpp"


namespace bitmq
{
    class SqliteHelper
    {
        typedef int (*sqliteCallback)(void*, int, char**, char**);
    public:
        SqliteHelper(const std::string& dbfile)
            : _dbfile(dbfile)
            , _handler(nullptr)
        {}

        bool open(int flag = SQLITE_OPEN_FULLMUTEX) //默认为串行化
        {
            //不存在则创建 | 以可读可写方式
            int ret = sqlite3_open_v2(_dbfile.c_str(), &_handler, SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE  | flag, nullptr);
            if (ret != SQLITE_OK)
            {
                ELOG("创建/打开sqlite数据库失败: %s", sqlite3_errmsg(_handler));
                return false;
            }
            return true;
        }

        bool exec(const std::string& sql, sqliteCallback cb, void* arg)
        {
            int ret = sqlite3_exec(_handler, sql.c_str(), cb, arg, nullptr);
            if (ret != SQLITE_OK)
            {
                ELOG("%s 执行语句失败: %s",sql.c_str(), sqlite3_errmsg(_handler));
                return false;
            }
            return true;
        }

        void close()
        {
            if (_handler)
                sqlite3_close_v2(_handler);
        }

    private:
        std::string _dbfile;
        sqlite3* _handler;
    };

    class StringHelper
    {
    public:
        static size_t splite(const std::string& str, const std::string& sep, 
                std::vector<std::string>& res)
        {
            int index = 0, pos = 0;
            while (index < str.size())
            {
                pos = str.find(sep, index);
                if (pos == std::string::npos)
                {
                    res.push_back(str.substr(index));
                    break;
                }

                if (index != pos)
                {
                    res.push_back(str.substr(index, pos - index));
                }
                index = pos + sep.size();
            }
            return res.size();
        }
    };

    class UUIDHelper
    {
    public:
        static std::string uuid()
        {
            std::random_device rd;
            std::mt19937_64 gernator(rd());
            //限制数字区间
            std::uniform_int_distribution<int> distribution(0, 255);
            //将生成的数字转换为16进制数字字符
            std::stringstream ss;
            for (int i = 0; i < 8; i++)
            {
                ss << std::setw(2) << std::setfill('0') << std::hex << distribution(gernator);
                if (i == 3 || i == 5 || i == 7)
                    ss << "-";
            }
        
            //定义一个原子类型整形，初始值为1
            static std::atomic<size_t> seq(1);
            size_t num = seq.fetch_add(1);
            for (int i = 7; i >= 0; i--)
            {
                ss << std::setw(2) << std::setfill('0') << std::hex << ((num >> (i * 8)) & 0xff);
                if (i == 6)
                    ss << "-";
            }
            return ss.str();
        }
    };

    class FileHelper
    {
    public:
        FileHelper(const std::string& filename)
            : _filename(filename)
        {}

        bool exists()  //判断是否存在
        {
            //使用stat获取文件状态，获取失败则表示文件不存在
            struct stat st;
            return stat(_filename.c_str(), &st) == 0;//成功返回0，不成功返回-1
        }

        size_t size()  //获取文件大小
        {
            struct stat st;
            int ret = stat(_filename.c_str(), &st);
            if (ret < 0)
                return 0;

            return st.st_size;
        }

        bool read(std::string& buffer)  //读取文件中所有内容到buffer中 
        {
            //获取文件大小，根据文件大小调整buffer的空间
            size_t fsize = size();
            buffer.resize(fsize);
            return read(&buffer[0], 0, fsize);
        }

        bool read(char* buffer, size_t offset, size_t len)  //从offset位置读取len个字符
        {
            //1.打开文件
            std::ifstream ifs(_filename, std::ios::binary | std::ios::in);
            if (ifs.is_open() == false)
            {
                ELOG("%s 文件打开失败", _filename.c_str());
                return false;
            }

            //2.跳转文件读写位置
            ifs.seekg(offset, std::ios::beg);

            //3.读取文件数据
            ifs.read(buffer, len);
            if (ifs.good() == false)
            {
                ELOG("% 文件读取数据失败", _filename.c_str());
                ifs.close();
                return false;
            }

            //4.关闭文件
            ifs.close();
            return true;
        }

        bool write(const std::string& buffer)   //将buffer写入文件当中
        {   
            return write(buffer.c_str(), 0, buffer.size());
        }

        bool write(const char* buffer, size_t offset, size_t len)  //将buffer写入指定位置
        {
            //1.打开文件
            std::fstream ofs(_filename, std::ios::binary | std::ios::out | std::ios::in); //跳转位置需要读权限
            if (ofs.is_open() == false)
            {
                ELOG("%s 文件打开失败, 失败原因：%s", _filename.c_str(), strerror(errno));
                return false;           
            }
            //2.跳转到文件指定位置
            ofs.seekp(offset, std::ios::beg);
            //3.写入数据
            ofs.write(buffer, len);
            if (ofs.good() == false)
            {
                ELOG("% 文件写入数据失败", _filename.c_str());
                ofs.close();
                return false;   
            }
            //4.关闭文件
            ofs.close();
            return true;
        }

        bool renameFile(const std::string& newName)  //修改文件名称
        {
            return ::rename(_filename.c_str(), newName.c_str()) == 0;
        }

        static bool createFile(const std::string& filename)  //创建文件
        {
            std::fstream ofs(filename, std::ios::binary | std::ios::out);
            if (ofs.is_open() == false)
            {
                ELOG("%s 文件打开失败", filename.c_str());
                return false;           
            }
            ofs.close();
            return true;
        }

        static bool removeFile(const std::string& filename)  //删除文件
        {
            return ::remove(filename.c_str()) == 0;
        }

        static bool createDirectory(const std::string& path) //创建目录
        {
            //多级路径创建中，需要从第一个父级目录开始创建
            size_t pos = 0, index = 0;
            while (index < path.size())
            {
                pos = path.find('/', index);
                if (pos == std::string::npos)
                {
                    return mkdir(path.c_str(), 0775) == 0;
                }
                std::string subpath = path.substr(0, pos);
                int ret = mkdir(subpath.c_str(), 0775);
                if (ret != 0 && errno != EEXIST)
                {
                    ELOG("创建目录 %s 失败, 失败原因：%s", subpath.c_str(), strerror(errno));
                    return false;
                }
                index = pos + 1;
            }
            return true;
        }

        static bool removeDirectory(const std::string& path) //删除目录
        {
            std::string cmd = "rm -rf " + path;
            return system(cmd.c_str()) != -1;
        }
        
        static std::string parentDirectory(const std::string& filename) //获取文件路径
        {
            size_t pos = filename.rfind('/');
            if (pos == std::string::npos)
            {
                //文件名没有/，返回当前目录
                return "./";
            }

            std::string path = filename.substr(0, pos);
            return path;
        }

    private:
        std::string _filename;
    };
}